﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;

using Qing.Lang;

namespace Qing.Std {

    class Cast : Native {
        public override string Name { get; set; } = "转换";
        public override string Desc { get; set; } = "参数1-字符串，参数2-任意，返回任意；第一个参数是转换的目标类型的字符串表示，第二个参数是要转换的数据";

        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {
            if(args.Count < 2 ) {
                return Expr.Err("转换函数的参数不足");
            }
            if (args[0].Tp != TP.Str) {
                return Expr.Err("转换函数的第一个参数必须为目标类型字符串");
            }

            try {
                switch (args[0].Str()) {
                    case "逻辑类型":
                        return new Expr(TP.Bool, args[1].ToBool());

                    case "整数类型":
                        if (args[1].Tp == TP.Int) {
                            return args[1].Dup();
                        } else if (args[1].Tp == TP.Str || args[1].Tp == TP.Rune) {
                            return new Expr(TP.Int, Convert.ToInt32(args[1].Str()));
                        } else if (args[1].Tp == TP.Float) {
                            return new Expr(TP.Int, (int)args[1].Float());
                        } else if (args[1].Tp == TP.Bool) {
                            return new Expr(TP.Int, (bool)args[1].Val! ? 1 : 0);
                        }
                        break;

                    case "小数类型":
                        if (args[1].Tp == TP.Float) {
                            return args[1].Dup();
                        }else if (args[1].Tp == TP.Str || args[1].Tp == TP.Rune) {
                            return new Expr(TP.Float, Convert.ToDecimal(args[1].Str()));
                        }else if (args[1].Tp == TP.Int) {
                            return new Expr(TP.Float, (decimal)args[1].Int());
                        }
                        break;

                    case "字符串类型":
                        if (args[1].Tp == TP.Str || args[1].Tp == TP.Rune) {
                            return new Expr(TP.Str, args[1].Str());
                        } else {
                            return new Expr(TP.Str, args[1].ToStr());
                        }


                }
            }catch(Exception e) {
                return Expr.Err("" + e.Message);
            }


            return Expr.Err("转换函数的参数错误");
        }

    }


    class DecimalRound : Native {
        public override string Name { get; set; } = "保留小数";
        public override string Desc { get; set; } = "参数1-小数，参数2-整数，返回小数；根据四舍五入设置小数位数，参数1为转换前的小数，参数2为要保留的小数位数";

        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj = null, List<Expr>? namedArgs = null) {
            if (args.Count < 2) {
                return Expr.Err("保留小数函数的参数不足");
            }
            if (args[0].Tp == TP.Float && args[1].Tp == TP.Int && args[1].Int() >= 0) {
                return new Expr(TP.Float, Math.Round(args[0].Float(), args[1].Int()));
            }

            return Expr.Err("保留小数函数的参数错误");
        }

    }


    class DecodeStr : Native {
        public override string Name { get; set; } = "解码字符串";
        public override string Desc { get; set; } = "参数1-二进制，可选参数2-字符串，返回字符串；根据第二个参数设置字符编码，默认为UTF8，对二进制数据解码为字符串";

        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {
            if (args.Count < 1) {
                return Expr.Err("解码字符串函数的参数不足");
            }
            if (args[0].Tp != TP.Bin) {
                return Expr.Err("解码字符串函数的第一个参数必须为二进制类型");
            }

            Encoding ec = Encoding.UTF8;

            if (args.Count > 1 && args[1].Tp == TP.Str) {
                string ecStr = args[1].Str();
                ec = EncodeUtil.parseEncode(ecStr);
            }

            try {
                Expr ret = new Expr(TP.Str, null);
                ret.Val = ec.GetString(args[0].Bin());
                return ret;
            } catch (Exception e) {
                return Expr.Err("解码字符串函数调用失败=>" + e.Message);
            }

            return Expr.Err("解码字符串函数的参数错误");
        }

    }

    class EncodeStr : Native {
        public override string Name { get; set; } = "编码字符串";
        public override string Desc { get; set; } = "参数1-字符串，可选参数2-字符串，返回二进制；根据第二个参数设置字符编码，默认为UTF8，将字符串编码为二进制";

        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null, List<Expr>? namedArgs=null) {
            if (args.Count < 1) {
                return Expr.Err("编码字符串函数的参数不足");
            }
            if (args[0].Tp != TP.Str) {
                return Expr.Err("编码字符串函数的第一个参数必须为字符串类型");
            }

            Encoding ec = Encoding.UTF8;

            if (args.Count > 1 && args[1].Tp == TP.Str) {
                string ecStr = args[1].Str();
                ec = EncodeUtil.parseEncode(ecStr);
            }

            try {
                Expr ret = new Expr(TP.Bin, null);
                ret.Val = ec.GetBytes(args[0].Str());
                return ret;
            } catch (Exception e) {
                return Expr.Err("编码字符串函数调用失败=>" + e.Message);
            }

            return Expr.Err("编码字符串函数的参数错误");
        }

    }

    public class EncodeUtil {
        public static Encoding parseEncode(string ecStr) {
            Encoding ec = Encoding.UTF8;
            switch (ecStr) {
                case "system":
                case "System":
                case "SYSTEM":
                    ec = Encoding.Default;
                    break;

                case "utf-8":
                case "UTF-8":
                case "utf8":
                case "UTF8":
                    break;

                case "ascii":
                case "ASCII":
                    ec = Encoding.ASCII;
                    break;

                case "Unicode":
                case "unicode":
                    ec = Encoding.Unicode;
                    break;

                case "Latin1":
                case "latin1":
                    ec = Encoding.Latin1;
                    break;

                case "utf-7":
                case "UTF-7":
                case "utf7":
                case "UTF7":
                    ec = Encoding.UTF7;
                    break;

                case "utf-32":
                case "UTF-32":
                case "utf32":
                case "UTF32":
                    ec = Encoding.UTF32;
                    break;
            }
            return ec;
        }
    }



}
